package websocket

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"net/http"
	"sync"
	"time"
)

// Client 表示 WebSocket 连接客户端
type Client struct {
	ID         int
	Conn       *websocket.Conn
	Hub        *Hub
	Send       chan []byte
	ReceiverID int
}

// Hub 结构体用于管理客户端连接和消息广播
type Hub struct {
	Clients    map[int]*Client
	Broadcast  chan []byte
	Register   chan *Client
	Unregister chan *Client
	Mutex      sync.Mutex
}

// NewHub 初始化集线器
func NewHub() *Hub {
	return &Hub{
		Clients:    make(map[int]*Client),
		Broadcast:  make(chan []byte),
		Register:   make(chan *Client),
		Unregister: make(chan *Client),
	}
}

// Run 处理客户端注册、注销以及消息广播
func (hub *Hub) Run() {
	for {
		select {
		case client := <-hub.Register:
			hub.Mutex.Lock()
			hub.Clients[client.ID] = client
			hub.Mutex.Unlock()
		case client := <-hub.Unregister:
			hub.Mutex.Lock()
			if _, ok := hub.Clients[client.ID]; ok {
				delete(hub.Clients, client.ID)
				close(client.Send)
			}
			hub.Mutex.Unlock()
		case message := <-hub.Broadcast:
			for _, client := range hub.Clients {
				select {
				case client.Send <- message:
				default:
					close(client.Send)
					delete(hub.Clients, client.ID)
				}
			}
		}
	}
}

// ServeWs 启动 WebSocket 服务并加载聊天记录
func ServeWs(w http.ResponseWriter, r *http.Request, userID int, receiverID int, hub *Hub) {
	conn, err := websocket.Upgrade(w, r, nil, 1024, 1024)
	if err != nil {
		http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
		return
	}

	client := &Client{
		ID:         userID,
		Conn:       conn,
		Hub:        hub,
		Send:       make(chan []byte),
		ReceiverID: receiverID,
	}

	// 注册客户端
	client.Hub.Register <- client
	// 若 userID 为 1，更新所有未读消息为已读，管理端的操作
	if userID == 1000000 {
		err = chatService.MarkMessagesAsRead(receiverID, userID-1000000+1)
		if err != nil {
			fmt.Println("Error marking messages as read:", err)
		}
	}
	// 获取并发送历史记录
	go func() {
		if receiverID != 0 {
			// 加载指定对话的历史记录
			history, err := chatService.GetChatHistory(userID, receiverID)
			if err == nil {
				for _, msg := range history {
					historyMessage, _ := json.Marshal(msg)
					client.Send <- historyMessage
				}
			}
			// 更新未读消息为已读
			err = chatService.MarkMessagesAsRead(receiverID, userID)
			if err != nil {
				return
			}
		} else {
			history, err := chatService.GetChatListHistory(userID)
			if err == nil {
				for _, msg := range history {
					messageWithInfo, _ := json.Marshal(msg)
					client.Send <- messageWithInfo
				}

			}
		}
	}()

	// 启动消息读写协程
	go client.writePump()
	go client.readPump()
}

// writePump 从 Send 通道中发送消息到 WebSocket 连接
func (c *Client) writePump() {
	ticker := time.NewTicker(60 * time.Second)
	defer func() {
		ticker.Stop()
		err := c.Conn.Close()
		if err != nil {
			return
		}
	}()

	for {
		select {
		case message, ok := <-c.Send:
			err := c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err != nil {
				return
			}
			if !ok {
				err := c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
				if err != nil {
					return
				}
				return
			}
			fmt.Println("发送消息22222222222222", c.ID, c.ReceiverID)
			w, err := c.Conn.NextWriter(websocket.TextMessage)
			if err != nil {
				return
			}
			_, err = w.Write(message)
			if err != nil {
				return
			}

			if err := w.Close(); err != nil {
				return
			}

		case <-ticker.C:
			err := c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err != nil {
				return
			}
			if err := c.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

// readPump 从 WebSocket 连接读取消息并处理已读状态
func (c *Client) readPump() {
	defer func() {
		c.Hub.Unregister <- c
		err := c.Conn.Close()
		if err != nil {
			return
		}
	}()

	for {
		_, message, err := c.Conn.ReadMessage()
		if err != nil {
			break
		}

		// 解析消息内容
		var msgData map[string]interface{}
		if err := json.Unmarshal(message, &msgData); err != nil {
			continue
		}

		// 检查消息类型是否为“已读”指令
		if msgType, ok := msgData["type"].(string); ok && msgType == "read" {
			_ = chatService.MarkMessagesAsRead(c.ReceiverID, c.ID)
			continue
		}

		// 若是普通消息，保存消息并批量标记未读消息为已读
		if err := chatService.SaveMessage(c.ID, c.ReceiverID, string(message)); err != nil {
			continue
		}

		// 当接收方回复时，批量标记之前的消息为已读
		_ = chatService.MarkMessagesAsRead(c.ReceiverID, c.ID)

		// 发送消息给指定接收者
		c.Hub.SendToSpecificUser(c.ID, c.ReceiverID, message)
	}
}

// SendToSpecificUser 发送消息给指定接收者，并标记为已读
func (hub *Hub) SendToSpecificUser(senderID int, receiverID int, message []byte) {
	hub.Mutex.Lock()
	defer hub.Mutex.Unlock()

	for _, client := range hub.Clients {
		// 检查是否目标用户的 `client.ID` 等于 `receiverID`
		if client.ID == receiverID {
			if client.ReceiverID == 0 {
				// 如果接受方的ID为1，且 `ReceiverID == 0`
				if receiverID == 1 {
					// 检查ID为1000000的客户是否在线
					targetClient, targetOnline := hub.Clients[1000000]
					if targetOnline && targetClient.ReceiverID == senderID {
						// 将消息直接发送给ID为1000000的客户
						select {
						case targetClient.Send <- message:
							fmt.Println("Message sent to client 1000000")
						default:
							// 避免阻塞，不关闭通道，进行日志记录
							fmt.Println("Send channel to client 1000000 is temporarily blocked.")
						}
						return // 消息已发送，结束
					}
				}

				// ReceiverID 为 0 时接收所有消息，附带发送者信息
				userInfo, err := chatService.FetchUserDetails(senderID)
				if err == nil {
					// 将用户信息附加到消息
					messageData := map[string]interface{}{
						"user":    userInfo,
						"message": string(message),
					}
					messageWithInfo, _ := json.Marshal(messageData)

					// 将消息发送给用户 `client`
					select {
					case client.Send <- messageWithInfo:
					default:
						// 避免阻塞，不关闭通道，进行日志记录
						fmt.Println("Send channel is temporarily blocked; message may retry.")
					}
				}
			} else {
				// ReceiverID 有效，直接发送消息
				select {
				case client.Send <- message:
					_ = chatService.MarkMessagesAsRead(client.ID, receiverID)
				default:
					// 避免阻塞，不关闭通道，进行日志记录
					fmt.Println("Direct send channel is blocked; consider optimizing channel handling.")
				}
			}
		}
	}
}
